package com.tn.rtdata.examples.stockticker.client;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Arrays;
import java.util.HashMap;
import javax.jms.ConnectionFactory;
import javax.swing.*;

import org.apache.xbean.spring.context.ClassPathXmlApplicationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.tn.openrpc.RemoteMethod;
import com.tn.openrpc.serialization.Serializer;
import com.tn.rtdata.DataSource;
import com.tn.rtdata.FillException;
import com.tn.rtdata.Session;
import com.tn.rtdata.SessionException;
import com.tn.rtdata.examples.stockticker.StockTick;
import com.tn.rtdata.jms.JmsDataSource;
import com.tn.rtdata.util.LiveMap;

/**
 * Program entry point.
 */
public class Runner
{
  private static final Logger LOGGER = LoggerFactory.getLogger(Runner.class);

  private static final String APPLICATION_CONTEXT_FILE = "stock-ticker-client/client.xml";
  private static final String BEAN_DATA_EVENT_STATS_UPDATE_METHOD = "dataEventStatsUpdateMethod";
  private static final String BEAN_FILL_START_METHOD = "fillStartMethod";
  private static final String BEAN_FILL_STOP_METHOD = "fillStopMethod";
  private static final String BEAN_QUEUE_STOCK_TICK_EVENT = "stockTickEventQueue";
  private static final String FILL_STOCK_TICK = "stockTickFill";
  private static final String PROPERTY_CLOSE_SESSION_ON_EXIT = "closeSessionOnExit";

  public static boolean running = true;

  /**
   * Program entry point.
   */
  public static void main(final String[] args)
  {
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
      APPLICATION_CONTEXT_FILE
    );
    applicationContext.start();

    final Session session = applicationContext.getBean(Session.class);

    @SuppressWarnings({"unchecked"})
    final DataSource<StockTick> stockTickDataSource = new JmsDataSource<StockTick>(
      session,
      FILL_STOCK_TICK,
      Arrays.asList(Arrays.copyOfRange(args, 1, args.length)),
      (RemoteMethod)applicationContext.getBean(BEAN_FILL_START_METHOD),
      (RemoteMethod)applicationContext.getBean(BEAN_FILL_STOP_METHOD),
      (RemoteMethod)applicationContext.getBean(BEAN_DATA_EVENT_STATS_UPDATE_METHOD),
      applicationContext.getBean(ConnectionFactory.class),
      applicationContext.getBean(BEAN_QUEUE_STOCK_TICK_EVENT).toString(),
      (Serializer<String>)applicationContext.getBean(Serializer.class)
    );

    SwingUtilities.invokeLater(
      new Runnable()
      {
        public void run()
        {
          try
          {
            new ClientFrame(
              args[0],
              new LiveMap<String, StockTick>(
                stockTickDataSource,
                new HashMap<String, StockTick>(),
                new StockTickKeyGetter()
              )
            ).addWindowListener(
              new WindowAdapter()
              {
                @Override
                public void windowClosing(WindowEvent e)
                {
                  try
                  {
                    stockTickDataSource.stop();

                    if (!System.getProperty(PROPERTY_CLOSE_SESSION_ON_EXIT, Boolean.FALSE.toString()).equalsIgnoreCase(Boolean.TRUE.toString()))
                    {
                      int result = JOptionPane.showOptionDialog(
                        e.getComponent(),
                        "Do you want to close the session?",
                        args[0],
                        JOptionPane.YES_NO_OPTION,
                        JOptionPane.QUESTION_MESSAGE, null,
                        new Object[]{"Yes", "No"},
                        "Yes"
                      );

                      if (result == 0)
                      {
                        session.close();
                      }
                    }
                    else
                    {
                      session.close();
                    }
                  }
                  catch (FillException e1)
                  {
                    JOptionPane.showMessageDialog(e.getComponent(), "Error closing fill.");
                  }
                  catch (SessionException e1)
                  {
                    JOptionPane.showMessageDialog(e.getComponent(), "Error closing session.");
                  }
                }
              }
            );
          }
          catch (FillException e)
          {
            LOGGER.error(e.getMessage(), e);
            System.exit(0);
          }
        }
      }
    );

    while (running)
    {
      sleep(1000);
    }
  }

  /**
   * Sleeps the calling thread for the specified number of <code>millis</code>.
   */
  private static void sleep(long millis)
  {
    try
    {
      Thread.sleep(millis);
    }
    catch (InterruptedException e)
    {
      //ignore.
    }
  }
}
